/*T32
	sample-Encoder-video.c

	Copyright (C) 2014 Ingenic Semiconductor Co.,Ltd
	The specific instructions for all API calls in this file can be found in the header file of the proj/sdk-lv3/include/api/cn/imp/

	This sample demonstrates how to capture the H264/H265 stream: main(h264/h265), sec(h265/h264)
			(note：
					tchn0----        chn3----        chn6----        chn0----
					tchn1---|Main    chn4---|Sec     chn7---|Thr     chn1---|Four
					tchn2----        chn5----        chn8----        chn2----
			)
	direct mode can be selected based on direct_switch.
	direct_switch = 1, One direct through: In this case,
		only the main stream of main camera can pass through directly, while the secondary stream of main camera can pass through non directly
	direct_switch = 2, Two direct through: In this case,
		only the main stream of main camera can pass through directly, while the secondary stream of main camera can pass through non directly;
		only the main stream of second camera can pass through directly, while the secondary stream of second camera can pass through non directly;
	direct_switch = 3, Three direct through: In this case,
		only the main stream of main camera can pass through directly, while the secondary stream of main camera can pass through non directly;
		only the main stream of second camera can pass through directly, while the secondary stream of second camera can pass through non directly;
		only the main stream of third camera can pass through directly, while the secondary stream of third camera can pass through non directly;
	direct_switch = 4, Four direct through: In this case,
		only the main stream of main camera can pass through directly, while the secondary stream of main camera can pass through non directly;
		only the main stream of second camera can pass through directly, while the secondary stream of second camera can pass through non directly;
		only the main stream of third camera can pass through directly, while the secondary stream of third camera can pass through non directly;
		only the main stream of fourth camera can pass through directly, while the secondary stream of fourth camera can pass through non directly;
*/

#include "sample-common.h"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define TAG "sample-Encoder-video"

extern struct chn_conf chn[];
extern int direct_switch;

static int byGetFd = 0;

// 声明全局停止标志，在main.c中定义
extern int stop;

// 声明视频流停止标志，在sample-common.c中定义
extern volatile int stop_stream_thread;
void SAMPLE_VENC_HandleSig(int signo)
{
    signal(SIGINT, SIG_IGN);
    signal(SIGTERM, SIG_IGN);

    if (SIGINT == signo || SIGTERM == signo)
    {
        printf("exit program\n");

        // 设置停止标志，通知所有线程退出
        stop = 0;
        
        // 设置视频流停止标志
        stop_stream_thread = 1;
        
        // 注意：不要在信号处理函数中调用复杂的清理函数，这可能导致死锁
        // 线程会根据stop标志自行清理资源
        
        printf("exit program ok\n");
    }
    exit(-1);
}

/*
 * 线程函数：经典 1080P 编码示例
 * 职责：完成系统、帧源、编码器、OSD 的初始化/绑定/启流/取流/回收全流程
 * 返回值：成功返回 NULL，失败直接 exit(-1)（保持原逻辑）
 */
void *SAMPLE_VENC_1080P_CLASSIC(void *p)
{
    int i = 0;
    int ret = 0;
    
    /* Step.1 System init */
    ret = sample_system_init();
    if (ret < 0) {
        IMP_LOG_ERR(TAG, "System init failed\n");
        return (void *)-1;  /* 返回错误指针，而不是直接退出 */
    }

    /* Step.2 FrameSource init */
    ret = sample_framesource_init();
    if (ret < 0) {
        IMP_LOG_ERR(TAG, "FrameSource init failed\n");
        // 初始化失败时需要清理已初始化的资源
        sample_system_exit();
        return (void *)-1;
    }

    /* Step.3 Encoder init */
    for (i = 0; i < FS_CHN_NUM; i++) {
        if (chn[i].enable) {
            ret = IMP_Encoder_CreateGroup(chn[i].index);
            if (ret < 0) {
                IMP_LOG_ERR(TAG, "Encoder CreateGroup(%d) failed\n", chn[i].index);
                // 清理已创建的资源
                for (i--; i >= 0; i--) {
                    if (chn[i].enable) {
                        IMP_Encoder_DestroyGroup(chn[i].index);
                    }
                }
                sample_framesource_exit();
                sample_system_exit();
                return (void *)-1;
            }
        }
    }

    ret = sample_video_init();
    if (ret < 0) {
        IMP_LOG_ERR(TAG, "Video init failed\n");
        // 清理编码器组
        for (i = 0; i < FS_CHN_NUM; i++) {
            if (chn[i].enable) {
                IMP_Encoder_DestroyGroup(chn[i].index);
            }
        }
        sample_framesource_exit();
        sample_system_exit();
        return (void *)-1;
    }

    /* Step.4 Bind */
    for (i = 0; i < FS_CHN_NUM; i++) {
        if (chn[i].enable) {
            ret = IMP_System_Bind(&chn[i].framesource_chn, &chn[i].imp_encoder);
            if (ret < 0) {
                IMP_LOG_ERR(TAG, "Bind FrameSource%d and Encoder%d failed\n", chn[i].framesource_chn.groupID, chn[i].imp_encoder.groupID);
                // 清理已绑定的通道
                for (i--; i >= 0; i--) {
                    if (chn[i].enable) {
                        IMP_System_UnBind(&chn[i].framesource_chn, &chn[i].imp_encoder);
                    }
                }
                // 清理其他资源
                sample_video_exit();
                for (i = 0; i < FS_CHN_NUM; i++) {
                    if (chn[i].enable) {
                        IMP_Encoder_DestroyGroup(chn[i].index);
                    }
                }
                sample_framesource_exit();
                sample_system_exit();
                return (void *)-1;
            }
        }
    }

    /* Step.5 Stream On */
    ret = sample_framesource_streamon();
    if (ret < 0) {
        IMP_LOG_ERR(TAG, "FrameSource StreamOn failed\n");
        // 清理绑定
        for (i = 0; i < FS_CHN_NUM; i++) {
            if (chn[i].enable) {
                IMP_System_UnBind(&chn[i].framesource_chn, &chn[i].imp_encoder);
            }
        }
        // 清理其他资源
        sample_video_exit();
        for (i = 0; i < FS_CHN_NUM; i++) {
            if (chn[i].enable) {
                IMP_Encoder_DestroyGroup(chn[i].index);
            }
        }
        sample_framesource_exit();
        sample_system_exit();
        return (void *)-1;
    }

    sleep(SLEEP_TIME);

    /* Step.6 Get stream */
    if (byGetFd) {
        ret = sample_get_video_stream_byfd();
        if (ret < 0) {
            IMP_LOG_ERR(TAG, "Get video stream byfd failed\n");
            // 清理资源
            sample_framesource_streamoff();
            for (i = 0; i < FS_CHN_NUM; i++) {
                if (chn[i].enable) {
                    IMP_System_UnBind(&chn[i].framesource_chn, &chn[i].imp_encoder);
                }
            }
            sample_video_exit();
            for (i = 0; i < FS_CHN_NUM; i++) {
                if (chn[i].enable) {
                    IMP_Encoder_DestroyGroup(chn[i].index);
                }
            }
            sample_framesource_exit();
            sample_system_exit();
            return (void *)-1;
        }
    } else {
        ret = sample_start_get_video_stream();
        if (ret < 0) {
            IMP_LOG_ERR(TAG, "Get video stream failed\n");
            // 清理资源
            sample_framesource_streamoff();
            for (i = 0; i < FS_CHN_NUM; i++) {
                if (chn[i].enable) {
                    IMP_System_UnBind(&chn[i].framesource_chn, &chn[i].imp_encoder);
                }
            }
            sample_video_exit();
            for (i = 0; i < FS_CHN_NUM; i++) {
                if (chn[i].enable) {
                    IMP_Encoder_DestroyGroup(chn[i].index);
                }
            }
            sample_framesource_exit();
            sample_system_exit();
            return (void *)-1;
        }
        
        // 等待停止信号，而不是直接调用sample_stop_get_video_stream
        // 这样线程可以持续运行，直到收到退出信号
        while (stop) {
            sleep(1);
        }
        
        // 收到停止信号后，停止视频流
        IMP_LOG_INFO(TAG, "Stopping video stream...\n");
        sample_stop_get_video_stream();
    }

    /* Step.7 Stream Off */
    ret = sample_framesource_streamoff();
    if (ret < 0) {
        IMP_LOG_ERR(TAG, "FrameSource StreamOff failed\n");
        // 即使streamoff失败，也尝试清理其他资源
        for (i = 0; i < FS_CHN_NUM; i++) {
            if (chn[i].enable) {
                IMP_System_UnBind(&chn[i].framesource_chn, &chn[i].imp_encoder);
            }
        }
        sample_video_exit();
        for (i = 0; i < FS_CHN_NUM; i++) {
            if (chn[i].enable) {
                IMP_Encoder_DestroyGroup(chn[i].index);
            }
        }
        sample_framesource_exit();
        sample_system_exit();
        return (void *)-1;
    }

    /* Step.8 UnBind */
    for (i = 0; i < FS_CHN_NUM; i++) {
        if (chn[i].enable) {
            ret = IMP_System_UnBind(&chn[i].framesource_chn, &chn[i].imp_encoder);
            if (ret < 0) {
                IMP_LOG_ERR(TAG, "UnBind FrameSource%d and Encoder%d failed\n", chn[i].framesource_chn.groupID, chn[i].imp_encoder.groupID);
                // 记录错误但继续清理其他资源
            }
        }
    }

    /* Step.9 Encoder exit */
    ret = sample_video_exit();
    if (ret < 0) {
        IMP_LOG_ERR(TAG, "Video exit failed\n");
        // 继续清理其他资源
    }

    for (i = 0; i < FS_CHN_NUM; i++) {
        if (chn[i].enable) {
            ret = IMP_Encoder_DestroyGroup(chn[i].index);
            if (ret < 0) {
                IMP_LOG_ERR(TAG, "Encoder DestroyGroup(%d) failed\n", chn[i].index);
                // 记录错误但继续清理其他资源
            }
        }
    }

    /* Step.10 FrameSource exit */
    ret = sample_framesource_exit();
    if (ret < 0) {
        IMP_LOG_ERR(TAG, "FrameSource exit failed\n");
        // 继续清理系统资源
    }

    /* Step.11 System exit */
    ret = sample_system_exit();
    if (ret < 0) {
        IMP_LOG_ERR(TAG, "System exit failed\n");
        // 记录错误但仍返回
    }

    // 线程函数正确返回NULL
    return NULL;
}


